#include "spk_camera.h"
#include "config.h"

#include "device_ctrl.h"

#define LOG_TAG "device_ctrl"
#define LOG_LVL LOG_LVL_INFO
#include "spk_ulog.h"

cls_device_ctrl::cls_device_ctrl(/* args */)
{
    fd = -1;
    fd_c = -1;
    notify_win = nullptr;
    thread = nullptr;
}

cls_device_ctrl::~cls_device_ctrl()
{
    if (fd >= 0)
        closesocket(fd);
    if (fd_c >= 0)
        closesocket(fd_c);
    fd = -1;
    fd_c = -1;
    notify_win = nullptr;
}

int cls_device_ctrl::run(string server_ip, int port)
{
    if (fd >= 0)
        return fd;

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = (server_ip == "") ? INADDR_ANY : inet_addr(server_ip.c_str());
    addr.sin_port = htons(port);

    /*创建socket*/
    fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (fd < 0)
    {
        LOG_E("tcp socket创建失败!");
        return -1;
    }

    /*本机作为服务器*/
    if (server_ip == "") // linux
    {
        REUSE_PORT(fd)
        /*绑定到指定端口*/
        int err = ::bind(fd, (struct sockaddr *)&addr, sizeof(addr));

        if (err < 0)
        {
            LOG_E("tcp socket绑定失败!");
            closesocket(fd);
            return -1;
        }

        /*监听客户端请求*/
        err = listen(fd, 1);

        if (err < 0)
        {
            LOG_E("socket监听失败!");
            closesocket(fd);
            return -1;
        }
        fd_c = 0;
    }
    /*本机作为客户端*/
    else
    {
        /*尝试连接服务器(设备端TCP端口)*/
        if (::connect(fd, (sockaddr *)&addr, sizeof(addr)) < 0)
        {
            LOG_E("连接设备(%s:%d)失败!", server_ip.c_str(), port);
            return -1;
        }
        fd_c = -1;
    }

    /*后台接收客户端连接请求*/
    /*同时在此线程接收控制指令，因此此应用不支持多个设备同时连接配置*/
    thread = new std::thread(cls_device_ctrl::recv_packet_thread, this);  // 真正创建的通信线程
    // recv_packet_thread(this);
    return fd;
}

int cls_device_ctrl::get_device_info(device_info *msg)
{
    int st = 0;
#ifdef _WIN32
#else
    st = init_file_decode("config.ini", msg);
    /*这里需要加入DHCP/IP/DNS等查询功能*/
#endif
    return st;
}

int cls_device_ctrl::set_device_info(device_info *msg)
{
    int st = 0;
#ifdef _WIN32
#else
    st = init_file_encode("config.ini", msg);
    /*这里需要加入DHCP/IP/DNS等设置功能*/

    // 目前所有逻辑都是先写入配置文件, 然后重启, 重新加载所有参数, 可以完成配置
#endif
    return st;
}

int cls_device_ctrl::reboot(void)
{
#ifdef _WIN32
    return send_packet(CMD_DEVICE_REBOOT, nullptr, 0, this);
#else
    /*获得当前配置*/
    int st = 0;
    /*这里加入设备复位指令*/
    send_packet(CMD_DEVICE_REBOOT_ACK, &st, 4, this);
    return st;
#endif
}

int cls_device_ctrl::refresh(void)
{
#ifdef _WIN32
    return send_packet(CMD_DEVICE_REFRESH, nullptr, 0, this);
#else
    /*获得当前配置*/
    struct device_info msg;
    int st = get_device_info(&msg); // 直接从配置文件里新读取的
    /*设置结果发送到PC*/
    if (st == SPK_ERR_NONE)
    {
        send_packet(CMD_DEVICE_REFRESH_ACK, &msg, sizeof(msg), this);
    }
    else
    {
        send_packet(CMD_DEVICE_REFRESH_ACK, &st, 4, this);
    }
    return st;
#endif
}

int cls_device_ctrl::ctrl(void *data)
{
    struct device_info msg;
    memcpy(&msg, data, sizeof(struct device_info));

#ifdef _WIN32
    return send_packet(CMD_DEVICE_CTRL, &msg, sizeof(msg), this);
#else
    /*设置设备参数并得到返回值*/
    int st = set_device_info(&msg);

    if (st == SPK_ERR_NONE)
    {
        get_device_info(&msg);
        send_packet(CMD_DEVICE_CTRL_ACK, &msg, sizeof(msg), this);
    }
    else
    {
        /*设置结果发送到PC*/
        send_packet(CMD_DEVICE_CTRL_ACK, &st, 4, this);
    }
    return st;
#endif
}

int cls_device_ctrl::on_refresh_ack(void *data, int len)
{
    int st = 0;
#ifdef _WIN32
    if (len == 4)
    {
    }
    else
    {
        int cmd = CMD_DEVICE_REFRESH_ACK;
        ::SendMessage(notify_win, MSG_DEVICE_CTRL, (WPARAM)dat, (LPARAM)&cmd);
    }
#else
#endif
    return st;
}

int cls_device_ctrl::on_ctrl_ack(void *data, int len)
{
    int st = 0;
#ifdef _WIN32
    if (len == 4)
    {
    }
    else
    {
        AfxMessageBox("设备配置成功!", MB_ICONINFORMATION);
    }
#else
#endif
    return st;
}

int cls_device_ctrl::on_reboot_ack(void *data, int len)
{
    int st = 0;
#ifdef _WIN32
    if (len == 4)
    {
    }
    else
    {
        AfxMessageBox("设备重启成功!", MB_ICONINFORMATION);
    }
#else
#endif
    return st;
}

void cls_device_ctrl::recv_packet_thread(void *arg)
{
    cls_device_ctrl *ins = (cls_device_ctrl *)arg;

    if (ins->fd_c == 0) // 说明此时是server端 linux
    {
        struct sockaddr_in client_addr;
        socklen_t sock_len = sizeof(client_addr);

        while (1)
        {
            /*接收客户端连接请求*/
            ins->fd_c = ::accept(ins->fd, (struct sockaddr *)&client_addr, &sock_len);

            if (ins->fd_c < 0)
            {
                LOG_E("控制端口socket accept失败!");
                ::closesocket(ins->fd);
                ins->fd = -1;
                return;
            }

            LOG_D("accept client(%u.%u.%u.%u)", client_addr.sin_addr.s_addr & 0xFF, (client_addr.sin_addr.s_addr >> 8) & 0xFF, (client_addr.sin_addr.s_addr >> 16) & 0xFF, (client_addr.sin_addr.s_addr >> 24) & 0xFF);

            /*接收客户端指令*/
            spk_packet::recv_packet_thread_ex(ins->io_read, ins->on_rx_packet, ins);
        }
    }
    else
    {
        /*接收服务器端指令*/
        spk_packet::recv_packet_thread_ex(ins->io_read, ins->on_rx_packet, ins);
    }
}

int cls_device_ctrl::io_write(void *data, int len, void *param)
{
    cls_device_ctrl *ins = (cls_device_ctrl *)param;
    int _fd = ins->fd_c > 0 ? ins->fd_c : ins->fd;
    int st = send(_fd, (const char *)data, len, 0);
    return st;
}

void cls_device_ctrl::on_rx_packet(void *rx_buffer, int len, u8 type, void *param)
{
    cls_device_ctrl *ins = (cls_device_ctrl *)param;

    switch (type)
    {
    case CMD_DEVICE_CTRL:
        ins->ctrl(rx_buffer);
        break;
    case CMD_DEVICE_REFRESH:
        ins->refresh();
        break;
    case CMD_DEVICE_REBOOT:
        ins->reboot();
        break;
    case CMD_DEVICE_CTRL_ACK:
        ins->on_ctrl_ack(rx_buffer, len);
        break;
    case CMD_DEVICE_REFRESH_ACK:
        ins->on_refresh_ack(rx_buffer, len);
        break;
    case CMD_DEVICE_REBOOT_ACK:
        ins->on_reboot_ack(rx_buffer, len);
        break;
    default:
        break;
    }
}

int cls_device_ctrl::io_read(void *data, int len, int time_out_ms, void *param)
{
    cls_device_ctrl *ins = (cls_device_ctrl *)param;
    int _fd = ins->fd_c > 0 ? ins->fd_c : ins->fd;
    int st = recv(_fd, (char *)data, len, 0);
    return st;
}
